﻿using System;
using System.Collections;
using System.Linq;
using System.ServiceModel.DomainServices.Client;

namespace BrasilFramework.Comum.Silverlight.Utilitario
{
    
    public static class DomainContextExtensao
    {

        /// <summary>
        /// Recursively Attaches entity loaded from Other DomainContext to 
        /// current specified DomainContext
        /// </summary>
        /// <param name="context">DomainContext where entity will be attached</param>
        /// <param name="entity">Entity loaded from other DomainContext</param>
        /// <remarks>By Akash Kava</remarks>
        /// <returns></returns>
        public static Entity Attach(this DomainContext context, Entity entity)
        {
            if (entity == null || entity.EntityState != EntityState.Detached)
                return entity;

            Entity newEntity = entity;

            Entity[] list = new[] { entity };
            foreach (Entity c in context.EntityContainer.LoadEntities(list,
               LoadBehavior.MergeIntoCurrent))
            {
                newEntity = c;
                break;
            }

            // recursively attach all entities..
            Type entityType = typeof(Entity);

            // get all navigation properties…
            Type type = entity.GetType();
            foreach (var item in type.GetProperties())
            {
                if (entityType.IsAssignableFrom(item.PropertyType))
                {
                    Entity navEntity = Attach(context, item.GetValue(entity, null)
                       as Entity);
                    item.SetValue(newEntity, navEntity, null);
                    continue;
                }

                if (!item.PropertyType.Name.StartsWith("EntityCollection")) continue;

                IEnumerable coll = (IEnumerable)item.GetValue(entity, null);
                coll.Cast<Entity>().ToList().ForEach(child => Attach(context, child));
                //dynamic dcoll = item.GetValue(newEntity, null);
                //foreach (Entity child in newList)
                //    dcoll.Add(child);
            }
            return newEntity;
        }

        /// <summary>
        /// Recursively detaches entities from DomainContext, this 
        /// method detaches every navigation properties
        /// of current Entity as well.
        /// </summary>
        /// <param name="context"></param>
        /// <param name="entity"></param>
        /// <param name="deep"></param>
        /// <remarks>By Akash Kava</remarks>
        public static void Detach(this DomainContext context, Entity entity, bool deep = true)
        {
            if (entity == null || entity.EntityState == EntityState.Detached)
                return;

            Type type = entity.GetType();

            //Load all EntityCollection navigation
            foreach (IEnumerable coll in (from item in type.GetProperties()
                                          where item.PropertyType.Name.StartsWith("EntityCollection")
                                          select item.GetValue(entity, null)).OfType<IEnumerable>())
                coll.Cast<Entity>().ToList();

            EntitySet nes = context.EntityContainer.GetEntitySet(type);
            nes.Detach(entity);

            if(!deep) return;

            Type entityType = typeof(Entity);

            // get all navigation properties…
            foreach (var item in type.GetProperties())
            {
                if (entityType.IsAssignableFrom(item.PropertyType))
                {
                    Detach(context, item.GetValue(entity, null) as Entity);
                    continue;
                }

                if (!item.PropertyType.Name.StartsWith("EntityCollection")) continue;
                IEnumerable coll = item.GetValue(entity, null) as IEnumerable;
                if (coll != null) 
                    coll.Cast<Entity>().ToList().ForEach(child => Detach(context, child));
            }
        }

    }

}